package jgespres;

import java.sql.*;
import java.util.*;
import java.util.logging.*;
import javax.swing.table.AbstractTableModel;

/**
 * Gestion d'un catalogue de thèmes de présentation
 * 
 * @author guerfyld
 * @version 2.0
 */
public class ThemesCatalog extends AbstractTableModel {
    // Connection à la Base de données
    private Connection conn;
    // Requêtes préparées
    private PreparedStatement selectThemes;
    private PreparedStatement insertTheme;
    private PreparedStatement updateTheme;
    private PreparedStatement deleteTheme;
    private PreparedStatement maxThemeIds;
    
    // Liste des Thèmes du catalogue
    private Map  listById;
    private List orderList;
    
    // Logger
    private Logger logger = Logger.getLogger("jgespres");

    // Regroupement des Thèmes par Date plannifiée
    private List listByDate;

    /**
     * Constructeur
     * 
     * @param  conn   Connection à une base JDBC
     */
    public ThemesCatalog(Connection connection) {
        // Initialisation
        listById  = new HashMap(500);
        orderList = new ArrayList(500);
        listByDate = new ArrayList(100);
        setConnection(connection);
    }

    /**
     * Affectation connection (Changment de base)
     * 
     * @param connection    Connection à une base JDBC
     */
    public void setConnection(Connection connection) {
        // Affectation connection
        conn = connection;
        try {
            // Préparation requêtes
            selectThemes = conn.prepareStatement("SELECT id, date, libS, libL, libXL FROM Themes ORDER BY date, libS");
            insertTheme = conn.prepareStatement("INSERT INTO Themes (id, date, libS, libL, libXL) VALUES(?, ?, ?, ?, ?)");
            updateTheme = conn.prepareStatement("UPDATE Themes SET date = ?, libS = ?, libL = ?, libXL = ? WHERE id = ?");
            deleteTheme = conn.prepareStatement("DELETE FROM Themes WHERE id = ?");
            maxThemeIds = conn.prepareStatement("SELECT count(*), max(id) FROM Themes");
            
            // Chargement initial de la liste des thèmes
            load(true);
            fireTableStructureChanged();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * (Re)chargement de la liste des thèmes
     * 
     * @param init  Vrai si initialisation, Faux si rechargement.
     * @return      Opération effectuée avec succès (Vrai/Faux)
     */
    private boolean load(boolean init) {
        Theme Thm;
        
        logger.log(Level.INFO, "Chargement ThemesCatalog...");
        // Initialisation listes des Thèmes
        if (init) listById.clear();
        orderList.clear();
        listByDate.clear();
        
        try {
            // Initialisations
            List listThm = null;
            java.sql.Date date = jgespres.NULLDATE;
            
            // Chargement liste des Thèmes
            ResultSet rs = selectThemes.executeQuery();
            while (rs.next()) {
                if (init) {
                    // Mise à jour infos Thème
                    Thm = new Theme();
                    Thm.setId(rs.getInt(1));
                    Thm.setDate(rs.getDate(2));
                    Thm.setIdent(rs.getString(3));
                    Thm.setLabel(rs.getString(4));
                    Thm.setLargeLabel(rs.getString(5));
                    listById.put(new Integer(Thm.getId()), Thm);
                }
                else {
                    // Récupération infos Thème
                    Thm = (Theme) listById.get(new Integer(rs.getInt(1)));
                    if (Thm == null) {
                        logger.log(Level.SEVERE, "ERREUR Thème id="+rs.getInt(1)+" non trouvé dans ThemesCatalog !");
                        continue;
                    }
                }
                
                // Gestion rupture date
                if ( !date.equals(Thm.getDate()) ) {
                    listThm = new ArrayList(10);
                    listByDate.add(listThm);
                    date = Thm.getDate();
                    logger.log(Level.FINEST, "Gestion nouvelle date "+date);
                }
                
                // Mise à jour positionnement thème
                Thm.setOrderPos(listByDate.size()-1);
                logger.log(Level.FINEST, "["+(listByDate.size()-1)+"]="+Thm);
                
                // Mise à jour Listes des thèmes
                listThm.add(Thm);
                orderList.add(Thm);
            }
            
            logger.log(Level.CONFIG, "- listByDate="+listByDate.size());
            logger.log(Level.CONFIG, "- orderList="+orderList.size());
            logger.log(Level.CONFIG, "- listById="+listById.size());
            logger.log(Level.INFO, "Chargement ThemesCatalog ok.");
            return true;
        }
        catch(Exception e) {
            logger.log(Level.SEVERE, "ERROR Chargement ThemesCatalog :");
            e.printStackTrace();
        }

        return false;
    }

    /**
     * 
     */
    public boolean reload() {
        return load(false);
    }
    
    /**
     * Renvoi le nombres de thèmes du catalogue
     * 
     * @return      Nombres de thèmes
     */
    public int getNbThemes() {
        return listById.size();
    }

    /**
     * Renvoi le n-éme thème du catalogue
     * 
     * @param orderPos   Rang du thème (0..n)
     * @return           N-éme thème du catalogue
     */
    public Theme getTheme(int orderPos) {
        return (Theme) orderList.get(orderPos);
    }

    /**
     * Renvoi un thème du catalogue
     * 
     * @param id        Id. interne du thème
     * @return          Thème
     */
    public Theme getThemeById(int id) {
        return (Theme) listById.get(new Integer(id));
    }

    /**
     * Ajoute un nouveau thème au catalogue
     * 
     * @param Thm   Thème à inserer
     * @return      Opération effectuée avec succès (Vrai/Faux)
     */
    public boolean addTheme(Theme Thm) {
        int id;
        
        try {
            // Calcul prochain id interne
            ResultSet rs = maxThemeIds.executeQuery();
            if (rs.next()) {
                if (rs.getInt(1) != 0)
                    id = rs.getInt(2) + 1;
                else 
                    id = 1;
                    
                // Mise à jour Base de données
                logger.log(Level.INFO, "Ajout Thème id=" + id);
                insertTheme.setInt(1, id);
                insertTheme.setDate(2, Thm.getDate());
                insertTheme.setString(3, Thm.getIdent());
                insertTheme.setString(4, Thm.getLabel());
                insertTheme.setString(5, Thm.getLargeLabel());
                insertTheme.executeUpdate();
                
                // Mise à jour Liste des éleves
                Thm.setId(id);
                listById.put(new Integer(Thm.getId()), Thm);
                
                return reload();
            }
        }
        catch(Exception e) {
            e.printStackTrace();
        }    
        
        return false;
    }
    
    /**
     * Supprime un thème du catalogue
     * 
     * @param orderPos   Rang du thème (0..n)
     * @return           Opération effectuée avec succès (Vrai/Faux)
     */
    public boolean delTheme(int orderPos) {
        // Mise à jour Base de données
        Theme Thm = getTheme(orderPos);
        int id = Thm.getId();
        logger.log(Level.INFO, "Suppression thème id=" + id);
        try {
            // Mise à jour Base de données
            deleteTheme.setInt(1, id);
            deleteTheme.executeUpdate();

            // Mise à jour Liste des éleves
            listById.remove(new Integer(id));
            return reload();
        }
        catch(Exception e) {
            logger.log(Level.SEVERE, "Erreur suppression thème ("+id+") :");
            e.printStackTrace();
        }    
        
        return false;   
    }
    
    /**
     * Mise à jour d'un Théme
     * 
     * @param Thm       Thème à mettre à jour
     * @return          Opération effectuée avec succès (Vrai/Faux)
     */
    public boolean updTheme(Theme Thm) {
        int id = Thm.getId();
        logger.log(Level.FINE, "Sauvegarde thème ("+id+")");
        try {
            updateTheme.setDate(1, Thm.getDate());
            updateTheme.setString(2, Thm.getIdent());
            updateTheme.setString(3, Thm.getLabel());
            updateTheme.setString(4, Thm.getLargeLabel());
            updateTheme.setInt(5, id);
            updateTheme.executeUpdate();
            
            return true;
        }
        catch(Exception e) {
            logger.log(Level.SEVERE, "Erreur sauvegarde thème ("+id+") :", e);
            e.printStackTrace();
        }

        return false;
    }
    
    /**
     * Renvoi nombres de dates planifiées
     * 
     * @return      Nombres de dates planifiées
     */
    public int getNbDates() {
        return listByDate.size();
    }
    
    /**
     * Renvoi position du thème dans dates planifiées
     * 
     * @param thmId     Id. thème
     * @return          Rang du thème dans dates plannifiées (0..n)
     */
    public int getDatePosTheme(int thmId) {
        Theme Thm = (Theme) listById.get(new Integer(thmId));

        return Thm.getOrderPos();
    }

    /**
     * Renvoi position d'une date dans dates planifiées
     * 
     * @param date      Date
     * @return          Rang de la date dans dates plannifiées (0..n)
     */
    public int getDatePos(java.sql.Date date) {
        for (int pos=0; pos<listByDate.size(); pos++) {
            if ( date.equals(getDate(pos)) )
                return pos;
        }
        
        return -1;
    }

    /**
     * Renvoi n-éme date planifiée
     * 
     * @param datePos   Rang dans dates plannifiées (0..n)
     * @return          Date planifiée
     */
    public java.sql.Date getDate(int datePos) {
        List listThm = (List) listByDate.get(datePos);
        Theme Thm = (Theme) listThm.get(0);
        
        return Thm.getDate();
    }

    /**
     * Renvoi Themes aux n-éme rang des dates planifiées
     * 
     * @param datePos   Rang dans dates plannifiées (0..n)
     * @return          Liste de Thèmes
     */
    public Theme[] getThemesDate(int datePos) {
        List listThm = (List) listByDate.get(datePos);
       
        return (Theme[]) listThm.toArray(new Theme[listThm.size()]);
    }
            
    //    *********************************
    //    AbstractTableModel Implementation
    //    *********************************
    
    /**
     * Renvoi le nom d'une colonne de la JTable
     * 
     * @param col    Numéro de la colonne (0..n)
     * @return       Nom de la colonne
     */
    public String getColumnName(int col) {
        try {
            return jgespres.getResourceString("Theme.Col" + Integer.toString(col));
        }
        catch(Exception e) {}

        return "";
    }

     /**
      * Renvoi le nombre de colonnes de la JTable
      * 
      * @return       Nombre de colonnes
      */
     public int getColumnCount() {
          return 4;
     }

     /**
      * Renvoi le nombre de lignes de la JTable
      * 
      * @return       Nombre de lignes
      */
     public int getRowCount() {
          return getNbThemes();
     }

     /**
      * Renvoi valeur d'une cellule de la JTable
      * 
      * @param row      Numéro de ligne de la JTable
      * @param col      Numéro de colonne de la JTable
      * @return         Valeur de la cellule
      */
     public Object getValueAt(int row, int col) { 
         switch(col) {
            case 0:
                return getTheme(row).getIdent();
                
            case 1:
                return getTheme(row).getDate();
             
            case 2:
                return getTheme(row).getLabel();
             
            case 3:
                return getTheme(row).getLargeLabel();           
         }

         return "";
     }
}